| Shell Extensions и как с ними
бороться Опубликовано: ceval , Включено: Jul-14-2006 Shell Extensions и как с ними боротьсяДумаю, вы замечали, что некоторые программы добавляют собственные пункты в системное контекстное меню. Например, WinRAR добавляет "Сжать" и "Распаковать в…", ICQ - "Переслать пользователю" и пр. Механизм, с помощью которого ваш код "внедряется" в оболочку Windows, называется Shell Extensions - именно о нем пойдет речь… Определения В дальнейшем, говоря "программист среднего уровня", мы будем подразумевать человека, который уже написал свой первый текстовый редактор и знаком с практикой создания собственных компонент. ![]() Shell Extensions - набор сервисных функций Windows API, призванный обеспечить расширение базовых функций оболочки Windows Explorer за счет наших надстроек. В числе основных функций Shell Extensions:
Итак… Для реализации задуманного нам понадобятся интерфейсы IContextMenu и IShellFolder. Указатель на главный интерфейс IshellFolder, соответствующий "Рабочему столу" оболочки, можно получить, используя функцию SHGetDesktopFolder, объявление которой выглядит так: Код: function SHGetDesktopFolder (var
ppshf: IShellFolder): HResult; stdcall;
![]() Для этого сначала используем метод из интерфейса IShellFolder: Код: function GetUIObjectOf (hwndOwner:
HWND; cidl: UINT; var apidl: PItemIDList;const riid:
TIID; prgfInOut: Pointer; out ppvOut): HResult;
stdcall; Параметры:
После использования этого оператора нам понадобится обратиться к функциям WinAPI - для работы с контекстными меню. Это, в первую очередь: Код: Function CreatePopupMenu: HMENU;
stdcall; Function TrackPopupMenu (hMenu: HMENU; uFlags: UINT; x, y, nReserved: Integer;hWnd: HWND; prcRect: PRect): BOOL; stdcall; Function DestroyMenu (Menu:HMENU):LogBool; stdcall; Синтаксис первой и последней функции, я думаю, понятен и без разъяснений. Функция TrackPopupMenu, собственно, и выводит на экран контекстное меню. Параметры этой функции принимают значения:
Возвращаемое значение показывает наличие команды или ее отсутствие. Если True - пользователь выбрал пункт; False - соответственно, не выбрал. А теперь - самое главное Ну что ж, сделали мы Menu - остается наполнить его содержимым, соответствующим нашему ShellObject. Для этого узнаем сначала его идентификатор (PItemIDList) - сделаем это при помощи метода ParseDisplayName из интерфейса IshellFolder. Этот метод объявлен следующим образом: Код: function ParseDisplayName
(hwndOwner: HWND;pbcReserved: Pointer; lpszDisplayName:
POLESTR; out pchEaten: ULONG;out ppidl: PItemIDList; var
dwAttributes: ULONG): HResult; stdcall; Расклад такой:
Но здесь следует проявлять осторожность. Как вы помните, нам нужно вывести контекстное меню для C:\Windows\NotePad.exe. Но сделать это прямо нельзя. Поэтому найдем сначала PItemIDList для папки C:\Windows - контейнера нашего NotePad.exe. Пишем: Код: OleCheck
(ShellFolder.ParseDisplayName (Handle,nil,StringToOleStr
(ExtractFileDir (ShellObject)),
FEaten,FItemIDList,FAtt)); где:
После удачного завершения надо бы перейти к классу родителя нашего NotePad.exe. Воспользуемся для этого функцией IShellFolder.BindToObject, объявленной следующим образом: Код: Function BindToObject (pidl:
PItemIDList; pbcReserved: Pointer;const riid: TIID; out
ppvOut): HResult; stdcall; Тут:
И после очередной строчки кода: Код: OleCheck (ShellFolder.BindToObject
(FItemIDList,nil,IID_IShellFolder,ShellFolder0)); мы получим в переменной ShellFolder0 указатель на интерфейс IShellFolder, соответствующий папке C:\Windows. Теперь мы можем узнать PItemIDList нашего NotePad: Код: OleCheck
(ShellFolder0.ParseDisplayName
(Handle,nil,StringToOleStr (ExtractFileName
(ShellObject)),FEaten,FItemIDList,FAtt)); Для чего все это было написано? Теперь мы без зазрений совести можем приступать к выводу нашего контекстного меню: Код: OleCheck
(ShellFolder0.GetUIObjectOf (Handle,1,FItemIDList,IID_IContextMenu,nil,ICM)); Menu:=CreatePopupMenu; Try ICM.QueryContextMenu (Menu,1,$7FFF,CMF_EXPLORE or CMF_CANRENAME); Command:=TrackPopupMenu (Menu, TPM_LEFTALIGN or TPM_LEFTBUTTON or TPM_RETURNCMD,100,100,0,Handle,nil); If Command then Что тут написано. Во-первых - вызов интерфейса IcontextMenu, сопряженного с объектом FItemIDList папки ShellFolder0. Во-вторых, создание дескриптора пустого контекстного меню; заполнение контекстного QueryContextMenu; использование команды TrackPopupMenu для вывода контекстного меню в точку (100, 100). Обработка результата команды TrackPopupMenu:
Недоработки… ...а где их нет? То есть, конечно, этот компонент работает, я его использую, но в нем (пока) отсутствуют некоторые полезные функции. К примеру, если вы заглянете в файл ShlObj.pas, то обнаружите, что там, помимо использованного нами интерфейса IcontextMenu, объявлены также интерфейсы IContextMenu2 и IContextMenu3, которые используются для расширения базовых функций интерфейса (к примеру, IContextMenu2 используется для работы с элементами подменю). Кроме того, небольшая доработка компонента даст возможность включать в него свои собственные пункты меню (сравните рис. 3 и рис. 4).
>Так что не стоит рассматривать эту статью как исчерпывающее руководство по Shell Extensions - она призвана всего лишь пробудить в вас аппетит к дальнейшим исследованиям. Автор: Михаил Продан
| ||||